package com.battch.netty.battcn_netty_5_1_1_jianmaqi;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.FixedLengthFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

public class EchoLengthServer {

	 public static void bind(int port) {
	        EventLoopGroup masterGroup = new NioEventLoopGroup();//线程组,含一组NIO线程,专门用来处理网络事件
	        EventLoopGroup workerGroup = new NioEventLoopGroup();
	        try {
	            ServerBootstrap bootstrap = new ServerBootstrap();//NIO服务端启动辅助类
	            bootstrap.group(masterGroup, workerGroup).channel(NioServerSocketChannel.class)
	                    .option(ChannelOption.SO_BACKLOG, 100)
	                    .handler(new LoggingHandler(LogLevel.DEBUG))
	                    .childHandler(new ChannelInitializer<SocketChannel>() {
	                        @Override
	                        protected void initChannel(SocketChannel channel) throws Exception {
	                            channel.pipeline().addLast(new FixedLengthFrameDecoder(EchoConstant.FRAME_LENGTH));
	                            channel.pipeline().addLast(new StringDecoder());
	                            channel.pipeline().addLast(new EchoLengthServer.EchoServerHandler());
	                        }
	                    });
	            //绑定端口，同步等待成功,
	            System.out.println("绑定端口,同步等待成功......");
	            ChannelFuture future = bootstrap.bind(port).sync();
	            //等待服务端监听端口关闭
	            future.channel().closeFuture().sync();
	            System.out.println("等待服务端监听端口关闭......");
	        } catch (Exception e) {
	            e.printStackTrace();
	        } finally {
	            //优雅退出释放线程池
	            masterGroup.shutdownGracefully();
	            workerGroup.shutdownGracefully();
	            System.out.println("优雅退出释放线程池......");
	        }
	    }
	
	 	private static class  EchoServerHandler extends ChannelHandlerAdapter {
	 		
	 		private int counter;

	        @Override
	        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
	            String body = (String) msg;
	            System.out.println("EchoLengthServer 接收到的消息 :" + body + "; 当前统计:" + ++counter);
	        }

	        @Override
	        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
	            //将消息队列中信息写入到SocketChannel中去,解决了频繁唤醒Selector所带来不必要的性能开销
	            //Netty的 write 只是将消息放入缓冲数组,再通过调用 flush 才会把缓冲区的数据写入到 SocketChannel
	            ctx.flush();
	        }

	        @Override
	        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
	            ctx.close();//发生异常时候，执行重写后的 exceptionCaught 进行资源关闭
	        }
	 		
	 	}
	
	    public static void main(String[] args) {
	        EchoLengthServer.bind(EchoConstant.ECHO_LENGTH_PORT);
	    }
	
	
}
